package com.apimanage.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.apimanage.gateway.config.RateLimitProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 网关限流过滤器
 * 用于控制API的调用频率，防止恶意请求
 */
@Component
@Slf4j
public class RateLimitFilter implements GlobalFilter, Ordered {

    @Autowired
    private RateLimitProperties rateLimitProperties;

    @Autowired
    @Qualifier("integerRedisTemplate")
    private RedisTemplate<String, Integer> redisTemplate;

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * Redis限流键前缀
     */
    private static final String RATE_LIMIT_PREFIX = "api_gateway_rate_limit:";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 如果限流功能未启用，则直接通过
        if (!rateLimitProperties.isEnabled()) {
            return chain.filter(exchange);
        }

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 获取请求路径
        String requestPath = request.getURI().getPath();
        log.debug("[RateLimitFilter] Processing request for path: '{}'", requestPath);

        // 检查是否为不需要限流的路径
        if (isExcludePath(requestPath)) {
            log.debug("[RateLimitFilter] Path '{}' is in exclude list, skipping rate limit", requestPath);
            return chain.filter(exchange);
        }

        // 获取限流键
        String limitKey = getLimitKey(request);
        if (StrUtil.isEmpty(limitKey)) {
            return chain.filter(exchange);
        }

        // 获取该路径的限流配置
        int requestsPerSecond = getRequestsPerSecond(requestPath);

        try {
            // 尝试增加计数器
            Long count = redisTemplate.opsForValue().increment(limitKey);
            if (count != null) {
                // 如果是第一次访问，设置过期时间
                if (count == 1) {
                    redisTemplate.expire(limitKey, 1, TimeUnit.SECONDS);
                }

                // 检查是否超过限流阈值
                if (count > requestsPerSecond) {
                    log.warn("[RateLimitFilter] Rate limit exceeded for key: '{}', count: {}", limitKey, count);
                    response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                    return response.setComplete();
                }
                
                log.debug("[RateLimitFilter] Request count for key: '{}', count: {}", limitKey, count);
            }
        } catch (Exception e) {
            log.error("[RateLimitFilter] Error during rate limiting: {}", e.getMessage(), e);
            // Redis异常时，不进行限流，直接通过
        }

        return chain.filter(exchange);
    }

    /**
     * 根据请求获取限流键
     */
    private String getLimitKey(ServerHttpRequest request) {
        String strategy = rateLimitProperties.getStrategy();
        String path = request.getURI().getPath();
        
        switch (strategy) {
            case "ip":
                // 从请求中获取客户端IP
                String clientIp = getClientIp(request);
                return RATE_LIMIT_PREFIX + "ip:" + clientIp + ":" + path;
            case "user":
                // 从请求头中获取用户信息，需要根据实际情况实现
                String userId = request.getHeaders().getFirst("X-User-Id");
                if (StrUtil.isNotEmpty(userId)) {
                    return RATE_LIMIT_PREFIX + "user:" + userId + ":" + path;
                }
                // 如果没有用户信息，默认使用IP策略
                String ip = getClientIp(request);
                return RATE_LIMIT_PREFIX + "ip:" + ip + ":" + path;
            case "path":
                // 只根据路径进行限流
                return RATE_LIMIT_PREFIX + "path:" + path;
            default:
                log.warn("[RateLimitFilter] Unknown rate limit strategy: {}", strategy);
                return null;
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(ServerHttpRequest request) {
        // 从X-Forwarded-For头获取IP，或直接获取请求的远程地址
        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
        if (StrUtil.isNotEmpty(xForwardedFor)) {
            // 多个IP时，取第一个
            return xForwardedFor.split(",")[0].trim();
        }
        return request.getRemoteAddress() != null ? request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
    }

    /**
     * 检查路径是否在排除列表中
     */
    private boolean isExcludePath(String path) {
        List<String> excludePaths = rateLimitProperties.getExcludePaths();
        if (excludePaths != null && !excludePaths.isEmpty()) {
            for (String pattern : excludePaths) {
                if (pathMatcher.match(pattern, path)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取路径的限流配置
     */
    private int getRequestsPerSecond(String path) {
        List<RateLimitProperties.PathRateLimitConfig> pathConfigs = rateLimitProperties.getPathConfigs();
        if (pathConfigs != null && !pathConfigs.isEmpty()) {
            for (RateLimitProperties.PathRateLimitConfig config : pathConfigs) {
                if (pathMatcher.match(config.getPathPattern(), path)) {
                    return config.getRequestsPerSecond();
                }
            }
        }
        // 默认使用全局配置
        return rateLimitProperties.getRequestsPerSecond();
    }

    @Override
    public int getOrder() {
        // 限流过滤器在IP过滤之后，认证之前执行
        return -99;
    }



}